package com.milo.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.WebStatFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import java.sql.SQLException;
import java.util.Arrays;

/**
 * druid 配置属性
 * 
 * @author xwtec
 */
@Slf4j
//@Configuration
public class DruidProperties
{
    @Value("${spring.datasource.druid.initialSize}")
    private int initialSize;

    @Value("${spring.datasource.druid.minIdle}")
    private int minIdle;

    @Value("${spring.datasource.druid.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.druid.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
    private int maxEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.druid.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.druid.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.druid.testOnReturn}")
    private boolean testOnReturn;
    
    @Value("${spring.datasource.druid.web-stat-filter.exclusions}")
    private String filterExclusions="";
    @Value("${spring.datasource.druid.web-stat-filter.profile-enable}")
    private String filterProfileEnable;
    @Value("${spring.datasource.druid.web-stat-filter.url-pattern}")
    private String filterUrlPattern;
    
    @Value("${spring.datasource.druid.filters}")
    private String filters;
    
    @Value("${spring.datasource.druid.connection-properties}")
    private String connectionProperties;
    @Value("${spring.datasource.druid.connection-error-retry-attempts}")
    private int errorRetryAttempts;

	/*
	 * @Value("${spring.datasource.druid.stat-view-servlet.url-pattern}") private
	 * String servleturlPattern;
	 * 
	 * @Value("${spring.datasource.druid.stat-view-servlet.allow}") private String
	 * servletAllow;
	 * 
	 * @Value("${spring.datasource.druid.stat-view-servlet.login-username}") private
	 * String servletUserName;
	 * 
	 * @Value("${spring.datasource.druid.stat-view-servlet.login-password}") private
	 * String servletPassword;
	 */
    @Value("${spring.datasource.druid.filter.stat.log-slow-sql}")
    private boolean logSlowSql;
    @Value("${spring.datasource.druid.filter.stat.slow-sql-millis}")
    private int slowSqlMillis;
    
    public DruidDataSource dataSource(DruidDataSource datasource)
    {
        try {
			/** 配置初始化大小、最小、最大 */
			datasource.setInitialSize(initialSize);
			datasource.setMaxActive(maxActive);
			datasource.setMinIdle(minIdle);

			/** 配置获取连接等待超时的时间 */
			datasource.setMaxWait(maxWait);

			/** 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒 */
			datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);

			/** 配置一个连接在池中最小、最大生存的时间，单位是毫秒 */
			datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
			datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);

			/**
			 * 用来检测连接是否有效的sql，要求是一个查询语句，常用select 'x'。如果validationQuery为null，testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
			 */
			datasource.setValidationQuery(validationQuery);
			/** 建议配置为true，不影响性能，并且保证安全性。申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效。 */
			datasource.setTestWhileIdle(testWhileIdle);
			/** 申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。 */
			datasource.setTestOnBorrow(testOnBorrow);
			/** 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。 */
			datasource.setTestOnReturn(testOnReturn);
			
			/** 配置扩展插件 */
			datasource.setFilters(filters);//配置扩展插件

			datasource.setConnectionProperties(connectionProperties);
			datasource.setConnectionErrorRetryAttempts(errorRetryAttempts);

			datasource.setProxyFilters(Arrays.asList(statFilter()));
		} catch (SQLException e) {
			log.error("datasource configuration initialization error", e);
		}
        return datasource;
    }
    
    @Bean
    public Filter statFilter() {
        StatFilter statFilter = new StatFilter();
        statFilter.setSlowSqlMillis(slowSqlMillis);
        statFilter.setLogSlowSql(logSlowSql);
        return statFilter;
    }
    
    /**
     * 注册一个StatViewServlet
     * @return ServletRegistrationBean
     */
	/*
	 * private ServletRegistrationBean druidServletInit() { ServletRegistrationBean
	 * reg = new ServletRegistrationBean(); reg.setServlet(new StatViewServlet());
	 * //添加初始化参数：initParams
	 * //这里可以访问http://localhost:8080/{servleturlPattern}/index.html进行访问填入密码后可以看到管理
	 * reg.addUrlMappings(servleturlPattern); reg.addInitParameter("loginUsername",
	 * servletUserName);//登录查看信息的账号 reg.addInitParameter("loginPassword",
	 * servletPassword);//登录查看信息的账号密码. reg.addInitParameter("resetEnable","false");
	 * //是否能够重置数据. reg.addInitParameter("allow", servletAllow); //白名单 return reg; }
	 * 
	 * @Bean public ServletRegistrationBean druidServlet() { return
	 * druidServletInit(); }
	 */
    
    
    /**
     *  注册一个：filterRegistrationBean
     * @return
     */
    private FilterRegistrationBean filterRegistrationBeanInit() {
        //创建过滤器
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        //设置过滤器过滤路径
        filterRegistrationBean.addUrlPatterns(filterUrlPattern);
        //忽略过滤的形式
        filterRegistrationBean.addInitParameter("exclusions", filterExclusions);
        filterRegistrationBean.addInitParameter("profileEnable", filterProfileEnable);
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        return this.filterRegistrationBeanInit();
    }

    /**
     * 必须加上static
     */
    @Bean
    public static PropertySourcesPlaceholderConfigurer loadProperties() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        return configurer;
    }
}
